import base64
import os
import subprocess
import json
# import wmi
import hashlib
import json
import os
import sys
import threading
import time
from datetime import datetime, timedelta

import ctypes
import asyncio
import platform
import traceback
from pathlib import Path
from urllib.parse import quote

from mitmproxy import http, options, ctx
from mitmproxy.net.server_spec import ServerSpec
from mitmproxy.tools.dump import DumpMaster
from mitmproxy.tools.main import mitmdump
from proxy import proxy

from proxy_manager import ProxyManager

CONFIG_FILE_PATH = "config.json"
# 配置常量
CA_CERT_NAME = "mitmproxy-ca-cert.cer"

# 店小秘
DXM_AUTH_URL = "https://www.dianxiaomi.com/api/userInfo.json"

# TEMU 处理
TEMU_HOST = "https://seller.kuajingmaihuo.com"
TEMU_QUAN_TUO_AUTH_URL = "https://seller.kuajingmaihuo.com/bg/quiet/api/mms/userInfo"

# TEMU 半托认证url
TEMU_BANTUO_AUTH_URL = "https://www.dianxiaomi.com/shop/list/pddkj.htm"
# TEMU_BANTUO_AUTH_URL = "https://agentseller.temu.com/api/seller/auth/userInfo"

# shein 半托认证url
SHEIN_BANTUO_AUTH_URL = "https://www.dianxiaomi.com/sheinProduct/add.htm"

PROXY_PORT = 18888
PX_PROXY_PORT = 18889

# 代理信息
proxy_ip = "127.0.0.1"
proxy_port = 7891
proxy_username = ""
proxy_password = ""


proxy_ip = "168.158.59.42"
proxy_port = 44444
proxy_username = "14afbec1061be"
proxy_password = "7e458caded"

# 构建上游代理URL
if proxy_username and proxy_password:
    # upstream_proxy = f"http://{proxy_username}:{proxy_password}@{proxy_ip}:{proxy_port}"
    upstream_proxy = f"http://{proxy_ip}:{proxy_port}"

else:
    upstream_proxy = f"http://{proxy_ip}:{proxy_port}"

class SystemProxyManager:
    """Windows系统代理管理工具"""
    REG_PATH = r"Software\Microsoft\Windows\CurrentVersion\Internet Settings"

    def __init__(self):

        self.original_settings = {}
        self.save_original_settings()

    def save_original_settings(self):
        """保存原始代理设置"""
        try:
            import winreg
            key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, self.REG_PATH)
            self.original_settings["ProxyEnable"] = winreg.QueryValueEx(key, "ProxyEnable")[0]
            self.original_settings["ProxyServer"] = winreg.QueryValueEx(key, "ProxyServer")[0]
            winreg.CloseKey(key)
        except FileNotFoundError:
            self.original_settings = {"ProxyEnable": 0, "ProxyServer": ""}

    def set_proxy(self, enable=True):
        """配置系统代理（带错误重试）"""
        # try:
        #     import winreg
        #     key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, self.REG_PATH, 0, winreg.KEY_WRITE)
        #     if enable:
        #         winreg.SetValueEx(key, "ProxyEnable", 0, winreg.REG_DWORD, 1)
        #         winreg.SetValueEx(key, "ProxyServer", 0, winreg.REG_SZ, f"127.0.0.1:{PROXY_PORT}")
        #     else:
        #         # 恢复原始设置时优先使用保存的值，否则使用默认值
        #         winreg.SetValueEx(key, "ProxyEnable", 0, winreg.REG_DWORD,
        #                          self.original_settings.get("ProxyEnable", 0))
        #         winreg.SetValueEx(key, "ProxyServer", 0, winreg.REG_SZ,
        #                          self.original_settings.get("ProxyServer", ""))
        #     winreg.CloseKey(key)
        #     self.refresh_settings()
        #     return True
        # except Exception as e:
        #     print(f"❌ 代理设置失败: {str(e)}")
        #     return False

        return True

    def refresh_settings(self):
        """刷新系统设置使代理生效"""
        try:
            INTERNET_OPTION_REFRESH = 37
            internet_set_option = ctypes.windll.Wininet.InternetSetOptionW
            internet_set_option(0, INTERNET_OPTION_REFRESH, 0, 0)
        except Exception as e:
            print(f"⚠️ 刷新设置失败: {str(e)}")


class CertificateInstaller:
    """CA证书安装工具（修复证书生成逻辑）"""

    @staticmethod
    def install_windows_ca():
        """自动安装CA证书到Windows系统信任存储区"""
        cert_dir = Path.home() / ".mitmproxy"
        print(f"📦 CA证书目录: {cert_dir}")
        cert_path = cert_dir / CA_CERT_NAME

        # ✅ 修复点：确保证书目录存在
        cert_dir.mkdir(parents=True, exist_ok=True)

        # ✅ 修复点：正确生成证书（避免路径错误）
        if not cert_path.exists():
            print("⚠️ 证书不存在，正在生成...")
            try:
                # 显式生成证书到目标目录
                mitmdump(args=["-q", "--set", f"confdir={cert_dir}"])
                print("✅ 证书生成成功")
            except (subprocess.CalledProcessError, subprocess.TimeoutExpired) as e:
                print(f"❌ 证书生成失败: {str(e)}")
                return False

        # ✅ 安装证书（带路径验证）
        try:
            if not cert_path.exists():
                raise FileNotFoundError(f"证书文件不存在: {cert_path}")

            install_cmd = f'certutil -addstore -f "Root" "{cert_path}"'
            subprocess.run(install_cmd, shell=True, check=True)
            print(f"🔒 证书已安装: {cert_path}")
            return True
        except (subprocess.CalledProcessError, FileNotFoundError) as e:
            print(f"❌ 证书安装失败: {e}")
            return False


# 自定义上下文标识符
TEMU_SELF_HEADER_FLAG = "anti-content"


class JsonModifier:
    """HTTP响应修改工具"""

    def request(self, flow: http.HTTPFlow):
        # if flow.server_conn.timestamp_start is None:
        print(f"请求开始时间未设置，正在设置...{flow.request.url}")
        # flow.server_conn.via = ServerSpec(("socks5",f"{proxy_ip}:{proxy_port}"))
        auth_str = f"{proxy_username}:{proxy_password}"
        encoded_auth = base64.b64encode(auth_str.encode()).decode()

        # 如果上游代理需要认证
        if proxy_username and proxy_password:

            # 使用小写的 header 名称
            flow.request.headers["Proxy-Authorization"] = f"Basic {encoded_auth}"

        is_temu_request = False
        # 设置TEMU本站上下文标志
        if TEMU_SELF_HEADER_FLAG in flow.request.headers:
            flow.__dict__["is_temu_request"] = 1
            is_temu_request = True
            print(f"识别到TEMU本站请求，跳过处理")
            return flow

        if is_temu_request:
            pass
        else:
            """还原请求头"""
            if flow.request.url.startswith(TEMU_HOST) or flow.request.url.startswith("https://agentseller.temu.com/"):
                print("检测到大卖家TEMU 请求，正在处理...")
                if "mallid" in flow.request.headers and TEMU_SELF_HEADER_FLAG not in flow.request.headers:
                    header_mallid = flow.request.headers["mallid"]

                    for original_id_str, new_id in self.mapping.items():
                        try:
                            if new_id == header_mallid:
                                flow.request.headers["mallid"] = original_id_str
                                print(f"mallid 还原成功: {header_mallid} -> {original_id_str}")
                                break
                        except Exception as e:
                            traceback.print_exc()
                            print(f"大卖家TEMU请求处理失败: {str(e)}")
                    print(f"还原后mallid：{flow.request.headers['mallid']}")

    def __init__(self):
        """初始化时加载配置文件"""
        self.config = self._load_config()
        self.mapping = self.config.get('mallid_mapping', {})

    def _load_config(self):
        """加载外部配置文件"""
        try:
            if os.path.exists(CONFIG_FILE_PATH):
                with open(CONFIG_FILE_PATH, 'r', encoding='utf-8') as f:
                    config = json.load(f)
                    print("✅ 配置文件加载成功")
                    return config
            else:
                raise FileNotFoundError(f"配置文件不存在: {CONFIG_FILE_PATH}")
        except Exception as e:
            print(f"❌ 配置文件加载失败: {str(e)}")
            raise e

    def response(self, flow: http.HTTPFlow):
        # 检查上下文标志
        if getattr(flow, "is_temu_request", 0) == 1:
            print("💡 检测到TEMU本站上下文标志，跳过处理")
            return
        else:
            self.add_temu_quantuo_rule(flow)
            self.add_temu_bantuo_rule(flow)
            self.add_shein_bantuo_rule(flow)
            self.add_temu_ads_rule(flow)

            # self.add_dxm_rule(flow)

    def add_temu_quantuo_rule(self, flow):
        # 全托
        if flow.request.url == TEMU_QUAN_TUO_AUTH_URL:
            print(f"🚀 命中TEMU全托拦截:{flow.request.url}")
            try:
                # 解析并修改JSON响应
                response = json.loads(flow.response.text)
                response_text = flow.response.text

                # 安全访问嵌套字段
                if (response.get("result", {}).get("companyList") and
                        response["result"]["companyList"][0].get("malInfoList") and
                        len(response["result"]["companyList"][0]["malInfoList"]) > 0):
                    pass
                    # # 获取原始mallId并转换为字符串进行匹配
                    # original_mallid = response["result"]["companyList"][0]["malInfoList"][0]["mallId"]
                    #
                    # # 只有在映射表中存在时才替换，否则保留原始值
                    # if str(original_mallid) in self.mapping:
                    #     new_mallid = self.mapping[str(original_mallid)]
                    #     response["result"]["companyList"][0]["malInfoList"][0]["mallId"] = new_mallid
                    #     print(f"✅ 映射成功: {original_mallid} → {new_mallid}")
                    # else:
                    #     print(f"ℹ️ 未找到匹配，保留原始值: {original_mallid}")

                else:
                    # 没有数据，则组装新数据
                    mock_json_data = '{"success":true,"errorCode":1000000,"errorMsg":null,"result":{"userId":10427381982257,"maskMobile":"+86 153****7996","maskOwnerMobile":"7996","accountType":1,"accountStatus":1,"tokenType":1,"companyList":[{"companyName":"-","malInfoList":[{"mallId":634418213187299,"mallName":"ouzhiluckyshop","logo":"https://img.cdnfe.com/supplier-public-tag/1f29b0ce60/466383dd-e0f6-49e2-b93c-43fcc780d78b_300x300.jpeg","mallStatus":1,"isSemiManagedMall":false},{"mallId":634418213741919,"mallName":"delilucluckshop","logo":"https://img.cdnfe.com/supplier-public-tag/1f29b0a1b0/93042c96-726f-4798-8b1b-8623ca95ce1a_300x300.jpeg","mallStatus":1,"isSemiManagedMall":false},{"mallId":634418213742069,"mallName":"DreamHomes","logo":"https://img.cdnfe.com/supplier-public-tag/1f135083f38/6387cc55-d7e8-4a58-8edc-1510c63219e1_300x300.jpeg","mallStatus":1,"isSemiManagedMall":true},{"mallId":634418216135768,"mallName":"OutdoorNestFurniture","logo":"https://img.cdnfe.com/supplier-public-tag/1f23584280/0b5bfff1-796b-4825-aa28-5b3e0d37c9f8_1000x1000.jpeg","mallStatus":1,"isSemiManagedMall":true},{"mallId":634418216135828,"mallName":"GreenGardenFurniture","logo":"https://img.cdnfe.com/supplier-public-tag/1f23584280/f6f376e8-b9c9-4075-9058-9369471688de_1000x1000.jpeg","mallStatus":1,"isSemiManagedMall":true}]}],"nickName":null,"roleNameList":["主账号"]}}'
                    print("mock数据")
                    response_text = mock_json_data

                # 遍历所有映射项，尝试匹配并替换
                for original_id_str, new_id in self.mapping.items():
                    try:
                        if original_id_str not in response_text:
                            continue
                        response_text = response_text.replace(original_id_str, new_id)
                        print(f"替换TEMU全托管成功: {original_id_str} -> {new_id}")
                    except ValueError:
                        print(f"⚠️ 非法ID格式: {original_id_str}")

                    # 移除压缩头防止解码错误
                    if "Content-Encoding" in flow.response.headers:
                        del flow.response.headers["Content-Encoding"]

                flow.response.text = response_text



            except (IndexError, KeyError, json.JSONDecodeError) as e:
                print(f"⚠️ TEMU全托JSON修改错误: {str(e)}")

    def add_shein_bantuo_rule(self, flow: http.HTTPFlow):
        if flow.request.url == "https://www.dianxiaomi.com/userTemplate/sheinAdd.htm?shopId=":
            print(f"🚀 命中SHEIN半托拦截:{flow.request.url}")

            response_text = flow.response.text
            for original_id_str, new_id in self.mapping.items():
                try:
                    if original_id_str not in response_text:
                        continue
                    response_text = response_text.replace(original_id_str, new_id)
                    print(f"替换shein半托管成功: {original_id_str} -> {new_id}")
                except ValueError:
                    print(f"⚠️ 非法ID格式: {original_id_str}")
            flow.response.text = response_text

    def add_temu_bantuo_rule(self, flow: http.HTTPFlow):
        if flow.request.url in self.config['TEMU']['auth_url']:
            print(f"🚀 命中TEMU半托拦截:{flow.request.url}")

            response_text = flow.response.text
            for original_id_str, new_id in self.mapping.items():
                try:
                    if original_id_str not in response_text:
                        continue
                    response_text = response_text.replace(original_id_str, new_id)
                    print(f"替换TEMu半托管成功: {original_id_str} -> {new_id}")
                except ValueError:
                    print(f"⚠️ 非法ID格式: {original_id_str}")

            flow.response.text = response_text

    def add_dxm_rule(self, flow):
        if flow.request.url == DXM_AUTH_URL:
            print(f"🚀 命中店小秘拦截:{flow.request.url}")

            response_text = flow.response.text
            for original_id_str, new_id in self.mapping.items():
                try:
                    if original_id_str not in response_text:
                        continue
                    response_text = response_text.replace(original_id_str, new_id)
                    print(f"替换店小秘成功: {original_id_str} -> {new_id}")
                except ValueError:
                    print(f"⚠️ 非法ID格式: {original_id_str}")

            flow.response.text = response_text

    def test(self):
        for original_id_str, new_id in self.mapping.items():
            response_text = "aaa123"
            if original_id_str not in response_text:
                continue
            try:
                response_text = response_text.replace(original_id_str, new_id)
                print(f"替换TEMU全托管成功: {original_id_str} -> {new_id}")
            except ValueError:
                print(f"⚠️ 非法ID格式: {original_id_str}")

            print(f"替换结果:{response_text}")

    # 批量添加广告功能
    def add_temu_ads_rule(self, flow):
        if flow.request.url == "https://us.ads.temu.com/api/v1/coconut/mall/query_mall_detail":
            print(f"🚀 命中temu批量添加广告功能拦截:{flow.request.url}")

            # 固定用这个店铺id
            FIX_MALL_ID = "634418215979225"

            origin_text = flow.response.text
            try:
                if "success" in origin_text:
                    json_data = flow.response.json()
                    if json_data['result'] and 'mall_id' in json_data['result']:
                        json_data['result']['mall_id'] = FIX_MALL_ID

                    flow.response.text = json.dumps(json_data)

                else:
                    print(f"temu 批量添加广告功能认证接口返回失败:{flow.response.text}")
            except Exception as e:
                print("X temu批量添加广告功能处理失败")
                traceback.print_exc()


# def generate_device_fingerprint():
#     """生成设备唯一指纹（基于主板和硬盘序列号）"""
#     try:
#         c = wmi.WMI()
#         # 获取主板序列号
#         motherboard = next((s.SerialNumber.strip() for s in c.Win32_BaseBoard()), None)
#         # 获取硬盘序列号
#         disk = next((d.SerialNumber.strip() for d in c.Win32_DiskDrive()), None)
#
#         if motherboard and disk:
#             # 组合生成设备指纹
#             raw_fingerprint = f"{motherboard}_{disk}".encode()
#             return hashlib.sha256(raw_fingerprint).hexdigest()
#         return None
#     except Exception as e:
#         print(f"⚠️ 设备指纹生成失败: {str(e)}")
#         return None


def check_authorization():
    """验证授权文件有效性"""
    try:
        with open("授权文件.txt", "r", encoding="utf-8") as f:
            data = json.load(f)

        # 验证文件格式
        if not all(key in data for key in ["license_key", "activation_time"]):
            print("❌ 授权文件格式错误")
            return False

        # 解析授权码
        license_key = data["license_key"]
        if not license_key.startswith("DXM_"):
            print("❌ 非法授权码格式")
            return False

        # 提取有效期信息
        parts = license_key.split("_")
        if len(parts) != 3:
            print("❌ 授权码格式错误")
            return False

        # 验证签名（使用预共享密钥）
        secret_key = b"dxm_proxy_auth_key_2023"
        expected_signature = parts[2]

        payload = f"{parts[1]}|{data['expiration_days']}".encode()
        actual_signature = hashlib.sha256(secret_key + payload).hexdigest()[:16]

        if expected_signature != actual_signature:
            print("❌ 授权码无效")
            return False

        # 验证有效期
        activation_time = datetime.fromisoformat(data["activation_time"])
        expiration_time = activation_time + timedelta(days=data['expiration_days'])
        if datetime.now() > expiration_time:
            print(f"❌ 授权已过期（有效期至{expiration_time.strftime('%Y-%m-%d')}）")
            return False

        print(f"✅ 授权验证成功，有效期至{expiration_time.strftime('%Y-%m-%d')}）")
        return True

    except FileNotFoundError:
        print("❌ 授权文件未找到")
        return False
    except json.JSONDecodeError:
        print("❌ 授权文件格式错误")
        return False
    except Exception as e:
        print(f"❌ 授权验证失败: {str(e)}")
        return False


async def start_mitmproxy():

    """启动mitmproxy代理服务器"""


    # upstream_proxy = "http://127.0.0.1:8118"
    print(f"🚀 启动代理服务: {upstream_proxy}")
    config = options.Options(
        listen_host="127.0.0.1",
        listen_port=PROXY_PORT,
        ssl_insecure=True,
        upstream_cert=False,
        # mode=["socks5"],
        # mode=["socks5"],
        # mode=["upstream:http://127.0.0.1:7890"]
        mode=[f"upstream:{upstream_proxy}"],

    )
    addons = [JsonModifier()]

    print(f"\n🔁 代理服务已启动 | 端口: {PROXY_PORT}")
    print("=" * 50)
    print("操作说明:")
    print("- 所有HTTP/HTTPS流量已通过本代理")
    print("- 按 Ctrl+C 退出程序并恢复设置")
    print("=" * 50)

    master = DumpMaster(config)
    master.addons.add(*addons)

    await master.run()


def main():
    # 判断是否为Windows系统
    if platform.system() == "Windows":
        print("✅ 当前系统是Windows")

        # 检查授权状态
        if not check_authorization():
            print("❌ 未通过授权验证，程序终止")
            input("按Enter键退出...")
            exit(1)

        # 检查管理员权限
        if ctypes.windll.shell32.IsUserAnAdmin() == 0:
            print("❌ 请以管理员身份运行此程序！")
            input("按Enter键退出...")
            exit(1)

        # 初始化代理管理器
        proxy_manager = SystemProxyManager()
        restore_proxy = False

        try:
            # 安装CA证书
            print("\n🔐 正在安装CA证书...")
            if CertificateInstaller.install_windows_ca():
                print("✅ CA证书安装成功")
                # 转发代理
                start_proxy_py(proxy_ip, PROXY_PORT, proxy_username, proxy_password)
                # 设置系统代理
                if proxy_manager.set_proxy(enable=True):
                    print(f"🌐 系统代理已设置: 127.0.0.1:{PROXY_PORT}")
                    restore_proxy = True

                    # 启动代理
                    asyncio.run(start_mitmproxy())
            else:
                print("程序终止：证书安装失败")
        except KeyboardInterrupt:
            print("\n🛑 用户中断操作")
        except Exception as e:
            print(f"🔥 未捕获的异常: {str(e)}")
            traceback.print_exc()
        finally:
            # 确保恢复代理设置
            if restore_proxy:
                try:
                    proxy_manager.set_proxy(enable=False)
                    print("✅ 系统代理已恢复")
                except Exception as e:
                    print(f"⚠️ 代理恢复警告: {str(e)}")
    else:
        print(f"❌ 当前系统不是Windows，请手动设置代理，端口为:{PROXY_PORT}")
        # 启动代理
        asyncio.run(start_mitmproxy())


import subprocess
import sys
import time
import socket

# 全局变量存储 proxy.py 进程
proxy_process = None


def start_proxy_py(proxy_host, proxy_port, proxy_username=None, proxy_password=None, listen_port=PX_PROXY_PORT):
    """
    使用 subprocess 启动 proxy.py
    """
    global proxy_process

    try:
        # 构建命令行参数
        cmd = [
            sys.executable, '-m', 'proxy',
            '--hostname', '127.0.0.1',
            '--port', str(listen_port)
        ]

        # 添加上游代理配置
        if proxy_username and proxy_password:
            upstream_url = f"http://{proxy_username}:{proxy_password}@{proxy_host}:{proxy_port}"
        else:
            upstream_url = f"http://{proxy_host}:{proxy_port}"

        # 使用正确的参数名 --upstream 而不是 -- upstream
        cmd.extend(['--upstream', upstream_url])

        print(f"🚀 启动 proxy.py 命令: {' '.join(cmd)}")

        # 启动 proxy.py 进程
        proxy_process = subprocess.Popen(
            cmd,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            text=True
        )

        # 等待启动完成
        for i in range(10):
            if proxy_process.poll() is not None:  # 进程已退出
                stdout, stderr = proxy_process.communicate()
                print(f"❌ proxy.py 启动失败: {stderr}")
                return False

            try:
                sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                result = sock.connect_ex(('127.0.0.1', listen_port))
                sock.close()
                if result == 0:
                    print(f"✅ proxy.py 启动成功，监听端口: {listen_port}")
                    return True
            except:
                pass
            time.sleep(1)

        print("⚠️ proxy.py 启动超时")
        return False

    except Exception as e:
        print(f"❌ 启动 proxy.py 时发生错误: {str(e)}")
        return False


def stop_proxy_py():
    """
    停止 proxy.py 进程
    """
    global proxy_process
    if proxy_process and proxy_process.poll() is None:  # 进程仍在运行
        proxy_process.terminate()
        try:
            proxy_process.wait(timeout=5)  # 等待最多5秒
            print("✅ proxy.py 已停止")
        except subprocess.TimeoutExpired:
            proxy_process.kill()  # 强制杀死进程
            print("⚠️ proxy.py 强制停止")
if __name__ == "__main__":
    # JsonModifier().test()
    main()
